/**
 * Created by XianTao on 2016/11/9
 * <p/>
 * Copyright (c) 2015-2015
 * Apache License
 * Version 2.0, January 2004
 * http://www.apache.org/licenses/
 */
package org.lego.jpa.base.util;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public class DynamicSpecifications {
    public static <T> Specification<T> buildSpecification(Map<String, Object> searchParams, final Class<T> entryClazz) {
        Map<String, SearchFilter> searchFilters = SearchFilter.parse(searchParams);
        return bySearchFilter(searchFilters.values(), entryClazz);
    }

    private static <T> Specification<T> bySearchFilter(final Collection<SearchFilter> filters, final Class<T> entryClazz) {
        return new Specification<T>() {
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                if (!CollectionUtils.isEmpty(filters)) {
                    List<Predicate> predicates = new ArrayList<Predicate>();
                    for (SearchFilter filter : filters) {
                        //如Task的名为"user.name"的filedName, 转换为Task.user.name属性
                        String[] names = {filter.fieldName};
                        if (filter.fieldName.contains(".")) {
                            names = StringUtils.split(filter.fieldName, ".");
                        }
                        Path expression = root.get(names[0]);
                        for (int i = 1; i < names.length; i++) {
                            expression = expression.get(names[i]);
                        }

                        switch (filter.operator) {
                            case EQ:
                                predicates.add(builder.equal(expression, filter.value));
                                break;
                            case LIKE:
                                predicates.add(builder.like(expression, "%" + filter.value + "%"));
                                break;
                            case LEFT_LIKE:
                                predicates.add(builder.like(expression, "%" + filter.value));
                                break;
                            case RIGHT_LIKE:
                                predicates.add(builder.like(expression, filter.value + "%"));
                                break;
                            case GT:
                                predicates.add(builder.greaterThan(expression, (Comparable) filter.value));
                                break;
                            case LT:
                                predicates.add(builder.lessThan(expression, (Comparable) filter.value));
                                break;
                            case GTE:
                                predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.value));
                                break;
                            case LTE:
                                predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.value));
                                break;
                            case ISNULL:
                                predicates.add(builder.isNull(expression));
                                break;
                            case ISNOTNULL:
                                predicates.add(builder.isNotNull(expression));
                                break;
                        }
                    }
                    //将所有条件用 and 联合起来
                    if (!predicates.isEmpty()) {
                        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
                    }
                }
                return builder.conjunction();
            }
        };
    }
}
